﻿using System;
using System.Collections.Generic;
using System.Linq;
using System.Windows.Forms;
using GraphViewer.Configuration;
using GraphViewer.Data;
using GraphViewer.Entity;
using Microsoft.Glee.Drawing;
using Microsoft.Glee.GraphViewerGdi;

namespace GraphViewer.View
{
    public partial class FormViewer : Form
    {
        #region Attributes

        private Graph _graph;
        private DataLoader _dataLoader;
        List<ProcessEntity> _controlMProcesses;
        private string _ctmFileName;
        private object _selectedObjectAttr;
        private object _selectedObject;
        private ToolTip _toolTip = new ToolTip();
        private List<Tuple<string, string>> _edges;

        #endregion

        #region Constructor

        public FormViewer()
        {
            InitializeComponent();

            _toolTip.Active = true;
            _toolTip.AutoPopDelay = 5000;
            _toolTip.InitialDelay = 1000;
            _toolTip.ReshowDelay = 500;
        }

        #endregion

        #region Events

        private void FormViewer_Load(object sender, EventArgs e)
        {
            _dataLoader = new DataLoader();

            LoadEnvironment();

            gViewerLocal.SelectionChanged += new EventHandler(gViewer_SelectionChanged);
            gViewerControlM.SelectionChanged += new EventHandler(gViewer_SelectionChanged);

            gViewerLocal.MouseEnter += new EventHandler(gViewer_MouseEnter);
            gViewerControlM.MouseEnter += new EventHandler(gViewer_MouseEnter);

            gViewerLocal.MouseWheel += new MouseEventHandler(gViewer_MouseWheel);
            gViewerControlM.MouseWheel += new MouseEventHandler(gViewer_MouseWheel);
        }

        private void gViewer_MouseEnter(object sender, EventArgs e)
        {
            Microsoft.Glee.GraphViewerGdi.GViewer gViewer = sender as Microsoft.Glee.GraphViewerGdi.GViewer;

            gViewer.Focus();
        }

        private void gViewer_MouseWheel(object sender, MouseEventArgs e)
        {
            Microsoft.Glee.GraphViewerGdi.GViewer gViewer = sender as Microsoft.Glee.GraphViewerGdi.GViewer;

            if (e.Delta > 0)
            {
                gViewer.ZoomInPressed();
            }
            else
            {
                gViewer.ZoomOutPressed();
            }

            if (gViewer.Graph != null)
            {
                float viewerX;
                float viewerY;

                gViewer.ScreenToSource(e.X, e.Y, out viewerX, out viewerY);
                gViewer.CenterToPoint(viewerX, viewerY);
            }
        }

        private void FormViewer_KeyDown(object sender, KeyEventArgs e)
        {
            if ((e.Modifiers & Keys.Control) > 0 && e.KeyCode == Keys.F)
            {
                FormSearch search = new FormSearch();

                if (search.ShowDialog() == System.Windows.Forms.DialogResult.OK)
                {
                    GViewer viewer = search.IsControlMSearch ? gViewerControlM : gViewerLocal;

                    var entity = viewer.Entities.ToList().Find(o =>
                        {
                            Microsoft.Glee.Node node = o.DrawingObject.GleeObject as Microsoft.Glee.Node;
                            bool found = false;

                            if (node != null)
                            {
                                found = node.Id == search.TextToSearch;
                            }

                            return found;
                        });

                    if (entity != null)
                    {
                        if (search.IsControlMSearch)
                        {
                            viewer.ShowBBox(((Microsoft.Glee.Node)entity.DrawingObject.GleeObject).BBox);
                        }
                        else
                        {
                            viewer.ShowBBox(((Microsoft.Glee.Node)entity.DrawingObject.GleeObject).BBox);
                        }
                    }
                }
            }
        }

        private void gViewer_SelectionChanged(object sender, EventArgs e)
        {
            Microsoft.Glee.GraphViewerGdi.GViewer gViewer = sender as Microsoft.Glee.GraphViewerGdi.GViewer;

            if (_selectedObject != null)
            {
                if (_selectedObject is Edge)
                {
                    (_selectedObject as Edge).Attr = _selectedObjectAttr as EdgeAttr;
                }
                else if (_selectedObject is Node)
                {
                    (_selectedObject as Node).Attr = _selectedObjectAttr as NodeAttr;
                }

                _selectedObject = null;
            }

            if (gViewer.SelectedObject == null)
            {
                gViewer.SetToolTip(_toolTip, "");
            }
            else
            {
                _selectedObject = gViewer.SelectedObject;

                if (_selectedObject is Edge)
                {
                    _selectedObjectAttr = (gViewer.SelectedObject as Edge).Attr.Clone();
                    (gViewer.SelectedObject as Edge).Attr.Color = Color.Magenta;
                    (gViewer.SelectedObject as Edge).Attr.Fontcolor = Color.Magenta;
                    Edge edge = gViewer.SelectedObject as Edge;
                    gViewer.SetToolTip(this._toolTip, String.Format("{0} -> {1}", edge.Source, edge.Target));
                }
                else if (_selectedObject is Node)
                {
                    _selectedObjectAttr = (gViewer.SelectedObject as Node).Attr.Clone();
                    (_selectedObject as Node).Attr.Color = Color.Magenta;
                    (_selectedObject as Node).Attr.Fontcolor = Color.Magenta;

                    ProcessEntity process = ((ProcessEntity)(_selectedObject as Node).UserData);

                    if (process != null)
                    {
                        gViewer.SetToolTip(_toolTip, process.ToString());
                        toolStripStatusLabel1.Text = process.ToString();
                    }
                }
            }

            gViewer.Invalidate();
        }

        private void btnHideLocal_Click(object sender, EventArgs e)
        {
            splitContainer1.Panel1Collapsed = !splitContainer1.Panel1Collapsed;
            btnHideLocal.Text = splitContainer1.Panel1Collapsed ? "=>" : "<=";
            btnHideControlM.Text = splitContainer1.Panel2Collapsed ? "<=" : "=>";
        }

        private void btnHideControlM_Click(object sender, EventArgs e)
        {
            splitContainer1.Panel2Collapsed = !splitContainer1.Panel2Collapsed;
            btnHideLocal.Text = splitContainer1.Panel1Collapsed ? "=>" : "<=";
            btnHideControlM.Text = splitContainer1.Panel2Collapsed ? "<=" : "=>";
        }

        private void btnComparer_Click(object sender, EventArgs e)
        {
            if (gViewerLocal.Graph != null && gViewerControlM.Graph != null)
            {
                using (FormComparer c = new FormComparer(_dataLoader.Processes, _controlMProcesses, _ctmFileName))
                {
                    c.ShowDialog();
                }
            }
        }

        private void btnExporter_Click(object sender, EventArgs e)
        {
            if (_dataLoader.Processes != null)
            {
                if (string.IsNullOrWhiteSpace(ddlEnvironmentControlM.Text))
                {
                    MessageBox.Show("Selecione o ambiente do Control-M que deseja exportar.");
                }
                else
                {
                    SaveFileDialog dialog = new SaveFileDialog();

                    dialog.Filter = "XML Files (*.xml)|*.xml";
                    dialog.Title = "Save Jobs";
                    dialog.RestoreDirectory = true;

                    if (dialog.ShowDialog() == DialogResult.OK)
                    {
                        ControlMLoader.Export(_dataLoader.Processes, dialog.FileName, ddlSystem.Text, ddlEnvironmentControlM.Text);
                    }
                }
            }
            else
            {
                MessageBox.Show("Faça uma pesquisa antes de exportar!");
            }
        }

        private void btnImport_Click(object sender, EventArgs e)
        {
            //GenerateLocalGraph("BBASQLATS4-64-M");
            //ControlMLoader.Export(_dataLoader.Processes, @"\\bbaprod4-ats\atsRisco\ProcessViewer\RSCI_ATS-S.xml", "PROD");
            //GenerateControlMGraph(@"\\bbaprod4-ats\atsRisco\ProcessViewer\RSCI_ATS-S.xml");
            //GenerateControlMGraph(@"\\bbaprod4-ats\atsRisco\ProcessViewer\BBAMTSN_NLB_RSCI_SYSTEM.xml");
            //return;

            OpenFileDialog dialog = new OpenFileDialog();

            dialog.Filter = "XML Files (*.xml)|*.xml";
            dialog.Title = "Open Jobs";
            dialog.RestoreDirectory = true;

            if (dialog.ShowDialog() == DialogResult.OK)
            {
                _ctmFileName = dialog.FileName;
                GenerateControlMGraph();
            }
        }

        private void btnView_Click(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(ddlEnvironmentLocal.Text) && !string.IsNullOrWhiteSpace(ddlSystem.Text))
            {
                GenerateLocalGraph(ddlEnvironmentLocal.Text, ddlSystem.Text);
            }
        }

        private void ddlEnvironmentLocal_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(ddlEnvironmentLocal.Text))
            {
                LoadSystems(ddlEnvironmentLocal.Text);
            }
        }

        private void ddlSystem_SelectedIndexChanged(object sender, EventArgs e)
        {
            if (!string.IsNullOrWhiteSpace(ddlEnvironmentLocal.Text) && !string.IsNullOrWhiteSpace(ddlSystem.Text))
            {
                LoadControlM(ddlSystem.Text);
            }
        }

        #endregion

        #region Methods

        private void LoadEnvironment()
        {
            foreach (DataBaseConfigurationElement item in EnvironmentConfigurationSection.GetSection().DataBases)
            {
                ddlEnvironmentLocal.Items.Add(item.ServerName);
            }
        }

        private void LoadSystems(string server)
        {
            ddlSystem.Items.Clear();

            foreach (string system in _dataLoader.LoadSystems(server))
            {
                ddlSystem.Items.Add(system);
            }
        }

        private void LoadControlM(string system)
        {
            ddlEnvironmentControlM.Items.Clear();

            if (EnvironmentConfigurationSection.GetSection().Systems[system] != null)
            {
                foreach (ControlMConfigurationElement item in EnvironmentConfigurationSection.GetSection().Systems[system].ControlM)
                {
                    ddlEnvironmentControlM.Items.Add(item.Name);
                }
            }
        }

        private void GenerateLocalGraph(string environment, string system)
        {
            _dataLoader.LoadData(environment, system);

            DrawingProcesses(_dataLoader.Processes);

            gViewerLocal.Graph = _graph;
            gViewerLocal.CalculateLayout(_graph);
        }

        private void GenerateControlMGraph()
        {
            _controlMProcesses = ControlMLoader.Read(_ctmFileName);

            DrawingProcesses(_controlMProcesses);

            gViewerControlM.Graph = _graph;
            gViewerControlM.CalculateLayout(_graph);
        }

        private void DrawingProcesses(List<ProcessEntity> processes)
        {
            _edges = new List<Tuple<string, string>>();
            _graph = new Graph("graph");

            foreach (var process in processes)
            {
                Node node = _graph.AddNode(process.ProcessId);

                foreach (var predecessor in process.Predecessors)
                {
                    AddEdge(predecessor, process.ProcessId);
                }

                foreach (var successor in process.Successors)
                {
                    AddEdge(process.ProcessId, successor);
                }

                node.UserData = new ProcessEntity() { ProcessId = process.ProcessId, ProcessName = process.ProcessName };

                SetStyle(process, node);
            }
        }

        private Edge AddEdge(string from, string to)
        {
            Edge edge = null;
            Tuple<string, string> tuple = Tuple.Create<string, string>(from, to);

            if (!_edges.Contains(tuple))
            {
                edge = _graph.AddEdge(from, to);
                _edges.Add(tuple);
            }

            return edge;
        }

        private void SetStyle(ProcessEntity process, Node node)
        {
            GroupEntity group = null;
            node.Attr.Fillcolor = GetColor(process.GroupId);

            if (_dataLoader.Groups != null && !string.IsNullOrEmpty(process.GroupId))
            {
                group = _dataLoader.Groups.Find(g => g.GroupId == process.GroupId);

                if ((process.ProcessId == _dataLoader.GetDummyJobName(true, process.GroupId)))
                {
                    node.Attr.Label = process.GroupId + " - " + group.GroupName;
                    node.Attr.Shape = Shape.Box;
                }

                if (process.ProcessId == _dataLoader.GetDummyJobName(false, process.GroupId))
                {
                    node.Attr.Label = string.Empty;
                    node.Attr.Shape = Shape.Point;
                    node.Attr.Fillcolor = Color.Black;
                }
            }

            node.Attr.Fontcolor = Color.Black;
        }

        private Color GetColor(string groupId)
        {
            int seed = 0;
            int.TryParse(groupId, out seed);

            if (seed == 0 && groupId != "0" && !string.IsNullOrEmpty(groupId))
            {
                int.TryParse(groupId.Length > 2 ? groupId.Substring(groupId.Length - 2) : groupId, out seed);
            }

            if (seed == 0)
            {
                seed = 1000; //System.Text.Encoding.ASCII.GetBytes(groupId).Sum(b => b);
            }

            if (groupId == "liberarisco")
                seed = 80;

            if (groupId == "NORISKSGFI")
                seed = 50;

            Random rnd = new Random(seed);

            return new Color((byte)rnd.Next(byte.MinValue, byte.MaxValue), (byte)rnd.Next(byte.MinValue, byte.MaxValue), (byte)rnd.Next(byte.MinValue, byte.MaxValue), (byte)rnd.Next(byte.MinValue, byte.MaxValue));
        }

        #endregion        
    }
}
